/*-------------------------------------------------------------------------
 *
 * bufmask.c
 *      Routines for buffer masking. Used to mask certain bits
 *      in a page which can be different when the WAL is generated
 *      and when the WAL is applied.
 *
 * Portions Copyright (c) 2016-2017, PostgreSQL Global Development Group
 *
 * This source code file contains modifications made by THL A29 Limited ("Tencent Modifications").
 * All Tencent Modifications are Copyright (C) 2023 THL A29 Limited.
 * 
 * Contains common routines required for masking a page.
 *
 * IDENTIFICATION
 *      src/backend/storage/buffer/bufmask.c
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include "access/bufmask.h"

/*
 * mask_page_lsn
 *
 * In consistency checks, the LSN of the two pages compared will likely be
 * different because of concurrent operations when the WAL is generated
 * and the state of the page when WAL is applied.
 */
void
mask_page_lsn(Page page)
{
    PageHeader    phdr = (PageHeader) page;

    PageXLogRecPtrSet(phdr->pd_lsn, (uint64) MASK_MARKER);
}

/*
 * mask_page_hint_bits
 *
 * Mask hint bits in PageHeader. We want to ignore differences in hint bits,
 * since they can be set without emitting any WAL.
 */
void
mask_page_hint_bits(Page page)
{
    PageHeader    phdr = (PageHeader) page;

    /* Ignore prune_xid (it's like a hint-bit) */
    phdr->pd_prune_xid = MASK_MARKER;
#ifdef __SUPPORT_DISTRIBUTED_TRANSACTION__
    phdr->pd_prune_ts = MASK_MARKER;
#endif

    /* Ignore PD_PAGE_FULL and PD_HAS_FREE_LINES flags, they are just hints. */
    PageClearFull(page);
    PageClearHasFreeLinePointers(page);

    /*
     * During replay, if the page LSN has advanced past our XLOG record's LSN,
     * we don't mark the page all-visible. See heap_xlog_visible() for
     * details.
     */
    PageClearAllVisible(page);
}

/*
 * mask_unused_space
 *
 * Mask the unused space of a page between pd_lower and pd_upper.
 */
void
mask_unused_space(Page page)
{
    int            pd_lower = ((PageHeader) page)->pd_lower;
    int            pd_upper = ((PageHeader) page)->pd_upper;
    int            pd_special = ((PageHeader) page)->pd_special;

    /* Sanity check */
    if (pd_lower > pd_upper || pd_special < pd_upper ||
        pd_lower < SizeOfPageHeaderData || pd_special > BLCKSZ)
    {
        elog(ERROR, "invalid page pd_lower %u pd_upper %u pd_special %u\n",
             pd_lower, pd_upper, pd_special);
    }

    memset(page + pd_lower, MASK_MARKER, pd_upper - pd_lower);
}

/*
 * mask_lp_flags
 *
 * In some index AMs, line pointer flags can be modified in master without
 * emitting any WAL record.
 */
void
mask_lp_flags(Page page)
{
    OffsetNumber offnum,
                maxoff;

    maxoff = PageGetMaxOffsetNumber(page);
    for (offnum = FirstOffsetNumber;
         offnum <= maxoff;
         offnum = OffsetNumberNext(offnum))
    {
        ItemId        itemId = PageGetItemId(page, offnum);

        if (ItemIdIsUsed(itemId))
            itemId->lp_flags = LP_UNUSED;
    }
}

/*
 * mask_page_content
 *
 * In some index AMs, the contents of deleted pages need to be almost
 * completely ignored.
 */
void
mask_page_content(Page page)
{
    /* Mask Page Content */
    memset(page + SizeOfPageHeaderData, MASK_MARKER,
           BLCKSZ - SizeOfPageHeaderData);

    /* Mask pd_lower and pd_upper */
    memset(&((PageHeader) page)->pd_lower, MASK_MARKER,
           sizeof(uint16));
    memset(&((PageHeader) page)->pd_upper, MASK_MARKER,
           sizeof(uint16));
}
